過去想要 LLMs 生成 json 格式的回應內容,只能從 Prompt 要求 LLMs 回應 json 格式,但是如果只是用文字描述,基於 LLMs 的隨機生成特性,會常出現不按牌理出牌。如果加上 Few-shot learning 則效果會好非常多,相對穩定,但依然會偶偶回了錯的格式,所以這時候通常會在程式中檢核 LLMs 回應的是否為 json 格式,如果發現不是 json 格式,就再重新發一次 LLMs 請求,通常很少連續2次都失敗的,至少我個人經驗是還沒遇過,不過這樣的策略滿浪費成本的。
而現在如果你使用的 LLMs 服務是 OpenAI 的話,那麼現在 OpenAI 的 API 提供了一個新參數,可以用於要求回應的內容以結構化的 Json 格式返回。當然 Semantic Kernel 也支援了這個選項。
假設情境是根據使用者提供的繁體中文內容,一次產生多國語言的翻譯內容,然後以 Json 格式返回。
var _kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
modelId: Config.openai_modelId,
apiKey: Config.openai_apiKey)
.Build();
var prompt = """
You are a translator who is proficient in multiple languages and has many years of experience in interpretation and book translation.
Now your task is to assist in translating the Traditional Chinese content provided by users into English, Japanese, Korean, and Simplified Chinese,
a total of 4 languages version.
### original content
{{$user_prompt}}
Please use the following json format for the output translation results.
### json format
{
"English": "translated content in English",
"Japanese": "translated content in Japanese",
"Korean": "translated content in Korean",
"Simplified_Chinese": "translated content in Simplified Chinese"
}
Note:
When translating please make sure:
1. Accuracy, the semantic meaning of the original Traditional Chinese content must not be lost
2. For fluency, please use common and everyday text expressions in the target language and avoid difficult text.
3. Ensure that the translation reflects the style of the original text
Do not provide any explanations or text apart from the translation.
Do not provide any explanations or text apart from the translation.
Do not provide any explanations or text apart from the translation.
""";
OpenAIPromptExecutionSettings promptExecutionSettings = new()
{
ResponseFormat = ChatResponseFormat.JsonObject,
MaxTokens = 1000,
Temperature = 0.2,
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
var arguments = new KernelArguments(promptExecutionSettings);
arguments.Add("user_prompt",
"""
• 本產品的上方和側邊不可置放任何物品,否則會干擾氣流,影響炸食結果。
• 使用產品時,請勿將產品放在可能會受蒸氣損壞的物品附近或下方,例如牆壁和櫥櫃。
• 將橡皮塞留在鍋裡。請勿在烹煮前將其移除。
""");
var result = await _kernel.InvokePromptAsync(promptTemplate: prompt, arguments: arguments);
Console.WriteLine(result.GetValue<string>());
生成結果:
{
"English": "Do not place any items on the top and sides of this product, as it may interfere with airflow and affect the cooking results. When using the product, do not place it near or below items that may be damaged by steam, such as walls and cabinets. Keep the rubber stopper in the pot. Do not remove it before cooking.",
"Japanese": "この製品の上部と側面に物を置かないでください。そうしないと、気流が妨げられ、調理結果に影響を与える可能性があります。製品を使用する際は、壁やキャビネットなど、蒸気によって損傷を受ける可能性のある物の近くや下に置かないでください。ゴム栓は 鍋の中に留めておいてください。調理前に取り外さないでください。",
"Korean": "이 제품의 상단과 측면에 물건을 놓지 마십시오. 그렇지 않으면 공기 흐름이 방해받아 조리 결과에 영향을 미칠 수 있습니다. 제품을 사용할 때는 벽이나 캐비닛과 같이 증기에 의해 손상될 수 있는 물건 근처나 아래에 두지 마십시오. 고무 마개는 냄비 안 에 두십시오. 요리 전에 제거하지 마십시오.",
"Simplified_Chinese": "本产品的上方和侧边不可放置任何物品,否则会干扰气流,影响烹饪结果。使用产品时,请勿将其放在可能会受蒸汽损坏的物品附近或下方,例如墙壁和橱柜。请将橡皮塞留在锅里,烹饪前请勿移除。"
}
當有整合外部系統需求時,要求 LLM 生成 JSON 結構化回應格式是非常有幫助的。舉例來說,在客服系統中,如果能從對話中自動整理出摘要、關鍵字及問題類型,並生成 JSON 格式,這些資料可以透過 API 回寫至客服記錄系統。再進一步延伸,這些資料也能用於統計分析。因此,能夠穩定輸出 JSON 格式的回應,對於 LLM 的應用發展是相當關鍵的。
目前,這類功能通常依賴平台的支援才能實現,否則只能透過設計 Prompt 來模擬(但這種方式相對不穩定且可靠性較低)。此外要注意的是,OpenAI 服務的這個參數,一旦設定 LLM 回應格式為 JSON,那麼所有回應都將會是 JSON 格式。因此,如果期待是在經過一連串對話後才產生 JSON 格式的回應,僅設置 ChatResponseFormat.JsonObject 是無法實現這樣的場景。此類需求會需要多個 Kernel 或 AI Agent 來協同運作(未來文章將進行此類實作示範)。
總結來說,生成 JSON 結構化回應格式,較適合在對話資料已經完整的情況下,進行一次性的回應生成應用。因此在這個範例中,是直接使用 kernel.InvokePromptAsync,而非使用 IChatCompletionService 的 GetChatMessageContentAsync 方法。